package com.diandian.backend.file.utils;

import com.diandian.base.boot.starter.exception.DefaultException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileTransferUtil {

    private static final Logger logger = LoggerFactory.getLogger(FileTransferUtil.class);

    private static SimpleDateFormat dateSdf = new SimpleDateFormat("yyyyMMdd");

    /**
     * 将文件保存到多层文件夹中，按照时间和数量分组
     * 说明：
     *      1. 第一层按照时间分组
     *      2. 第二层按照数量分组，超过置顶数量则产生新的文件夹
     *
     * @param urlString
     * @param basePath 存储文件到根路径，包含最后的/
     * @param fileName 保存的文件名
     * @param singleDirectoryMaxFileCount 单个文件夹最大文件数量
     * @return 文件保存到绝对路径
     */
    public static String saveToLocalMultiPath(String urlString, String basePath, String fileName, int singleDirectoryMaxFileCount) {

        // 根据时间计算文件夹层级
        String timePath = basePath + File.separator + dateSdf.format(new Date());
        File timeDirectory = new File(timePath);
        if(!timeDirectory.exists()){
            logger.info(timePath + "文件夹不存在，创建文件夹");
            timeDirectory.mkdirs();
        }

        // 计算数量层级，超过指定数量则产生新的文件夹
        String countDirectoryName = getMaxNameDirectory(timePath, singleDirectoryMaxFileCount);

        // 计算最终的文件绝对路径
        String filePath = timePath + File.separator + countDirectoryName + File.separator + fileName;
        logger.info("将要保存文件{} ...", filePath);

        // 保存文件
        boolean saveResult = saveUrlFileToLocal(urlString, filePath);
        logger.info("保存文件{}结果：{}", filePath, saveResult ? "成功" : "失败");

        return filePath;
    }

    /**
     * 获取置顶文件夹下的名称最大的文件夹名称
     * 说明：名称规则从1开始的数字
     * @param directory 指定的文件夹
     * @return 名称最大的文件夹名称，不存在则返回空
     */
    private static String getMaxNameDirectory(String directory, int singleDirectoryMaxFileCount){
        File pathFile = new File(directory);
        if(!pathFile.isDirectory()){
            logger.info(directory + "不是一个文件夹，停止后续处理");
            throw new DefaultException(directory + "不是一个文件夹");
        }
        if(!pathFile.exists()){
            logger.info(directory + "文件夹不存在，创建文件夹");
            pathFile.mkdirs();
        }

        File[] nextFileList = pathFile.listFiles();
        if(nextFileList == null || nextFileList.length == 0){
            String firstDirectoryName = "1";
            logger.info(directory + "文件夹下为空，创建文件夹第一个文件夹: {}", firstDirectoryName);
            new File(directory + File.separator + firstDirectoryName).mkdirs();
            return firstDirectoryName;
        }

        int maxNameDirectoryValue = 0;
        int maxNameDirectoryFileCount = 0;
        for (File file : nextFileList) {
            if (file.isDirectory()) {
                int nameValue = Integer.parseInt(file.getName());
                if(nameValue > maxNameDirectoryValue){
                    maxNameDirectoryValue = nameValue;
                    maxNameDirectoryFileCount = file.listFiles().length;
                }
            }
        }

        if(maxNameDirectoryFileCount >= singleDirectoryMaxFileCount){
            String nextDirectoryName = String.valueOf(maxNameDirectoryValue + 1);
            logger.info("切换新的文件夹{}中，将要创建文件夹...", nextDirectoryName);
            new File(directory + File.separator + nextDirectoryName).mkdirs();
            return nextDirectoryName;
        }
        return String.valueOf(maxNameDirectoryValue);
    }

    /**
     * 保存线上附件到本地
     * @param urlString
     * @param filePath
     * @return
     */
    public static boolean saveUrlFileToLocal(String urlString, String filePath) {
        boolean resultFlag = false;

        InputStream in = null;
        try {
            URL url = new URL(urlString);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            // 连接服务器
            connection.connect();
            // 检查响应码是否为200
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                in = connection.getInputStream();
                // 使用try-with-resources来自动关闭OutputStream
                try (OutputStream out = new FileOutputStream(filePath)) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    // 从输入流中读取数据，并写入到文件输出流中
                    while ((bytesRead = in.read(buffer)) != -1) {
                        out.write(buffer, 0, bytesRead);
                    }
                }
                // 注意：由于使用了try-with-resources，OutputStream会在这里自动关闭
                // 但我们仍然需要确保InputStream在方法结束时被关闭
                resultFlag = true;
            } else {
                System.out.println("Failed to download file: HTTP error code " + connection.getResponseCode());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭InputStream
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return resultFlag;
    }

}
